package cn.cachalot.oj.service.impl;

import cn.cachalot.oj.controller.res.CopyCheckRes;
import cn.cachalot.oj.controller.res.TestCaseInfoRes;
import cn.cachalot.oj.dao.CheckResult;
import cn.cachalot.oj.entity.CopiedSubmit;
import cn.cachalot.oj.entity.Solution;
import cn.cachalot.oj.entity.Submit;
import cn.cachalot.oj.mapper.CopiedSubmitMapper;
import cn.cachalot.oj.mapper.SolutionMapper;
import cn.cachalot.oj.mapper.SubmitMapper;
import cn.cachalot.oj.mapper.UserMapper;
import cn.cachalot.oj.service.CopyCheckService;
import cn.cachalot.oj.service.SolutionService;
import cn.cachalot.oj.service.UserService;
import cn.cachalot.oj.util.CheckCopy;
import lombok.SneakyThrows;
import org.apache.ibatis.annotations.Result;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class CopyCheckServiceImpl implements CopyCheckService {
    @Resource
    SolutionMapper solutionMapper;
    @Resource
    SubmitMapper submitMapper;
    @Resource
    CopiedSubmitMapper copiedSubmitMapper;
    @Resource
    CheckCopy checkCopy;
    @Resource
    UserMapper userMapper;

    @SneakyThrows
    @Override
    @Transactional
    public CheckResult checkBySubmit(Submit submit) {
        String currentCode = submit.getCode();
        CheckResult checkResult = new CheckResult();
        checkResult.setCurrentSubmit(submit);
        List<Solution> solutionList =
                solutionMapper.getSolutionListByProblemIdAndLanguage(submit.getProblemId(), submit.getLanguage());
        if (solutionList == null) {
            checkResult.setIsCopied(false);
            submit.setStatus(6);
            submitMapper.updateById(submit);
            Solution solution = new Solution();
            BeanUtils.copyProperties(submit, solution);
            solutionMapper.insert(solution);
            return checkResult;
        }
        for (Solution solution : solutionList) {
            String code = solution.getCode();
            Double similarRate = checkCopy.check(currentCode, code);
            if (similarRate >= 0.7) {
                if (Objects.equals(submit.getUserId(), submitMapper.getUserIdBySubmitId(solution.getId()))) {
                    checkResult.setIsCopied(false);
                    submit.setStatus(6);
                    submitMapper.updateById(submit);
                    return checkResult;
                }
                checkResult.setIsCopied(true);
                checkResult.setSimilarRate(similarRate);
                checkResult.setCopiedSubmitId(solution.getId());
                submit.setStatus(5);
                submitMapper.updateById(submit);
                CopiedSubmit copiedSubmit = new CopiedSubmit();
                copiedSubmit.setId(submit.getId());
                copiedSubmit.setCopiedId(solution.getId());
                copiedSubmitMapper.insert(copiedSubmit);
                return checkResult;
            }
        }
        checkResult.setIsCopied(false);
        submit.setStatus(6);
        submitMapper.updateById(submit);
        Solution solution = new Solution();
        BeanUtils.copyProperties(submit, solution);
        solutionMapper.insert(solution);
        return checkResult;
    }

    @Override
    @Transactional
    public List<CheckResult> checkAll() {
        List<CheckResult> checkResultList = new ArrayList<>();
        List<Submit> submitList = submitMapper.getUncheckedSubmitList();
        if (submitList == null) {
            return null;
        }
        CheckResult checkResult;
        for (Submit submit : submitList) {
            checkResult = checkBySubmit(submit);
            if (checkResult.getIsCopied()) {
                checkResultList.add(checkResult);
            }
        }
        return checkResultList;
    }

    @Override
    @Transactional
    public List<CopyCheckRes> getCheckAllCopyCheckResList() {
        List<CheckResult> checkResultList = checkAll();
        if (checkResultList == null) {
            return null;
        }
        List<CopyCheckRes> resList = checkResultList.stream().map(item -> {
            Submit copiedSubmit = submitMapper.selectById(item.getCopiedSubmitId());
            CopyCheckRes copyCheckRes = new CopyCheckRes();
            copyCheckRes.setSubmitId(item.getCurrentSubmit().getId());
            copyCheckRes.setSubmitTime(item.getCurrentSubmit().getSubmitTime());
            copyCheckRes.setCode(item.getCurrentSubmit().getCode());
            copyCheckRes.setUserId(item.getCurrentSubmit().getUserId());
            copyCheckRes.setUserName(userMapper.getUserNameByUserId(item.getCurrentSubmit().getUserId()));
            copyCheckRes.setProblemId(item.getCurrentSubmit().getProblemId());
            copyCheckRes.setSimilarRate(item.getSimilarRate());
            copyCheckRes.setCopiedCode(copiedSubmit.getCode());
            copyCheckRes.setCopiedSubmitTime(copiedSubmit.getSubmitTime());
            return copyCheckRes;
        }).collect(Collectors.toList());
        return resList;
    }
}
